﻿using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.Animation;
using System.Diagnostics;

namespace CardGame
{
    /// <summary>
    /// 继承接口 IComparer 实现随机乱序
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class RandomComparer<T> : IComparer<T>
    {
        Random rdm = new Random(DateTime.Now.Millisecond);

        public int Compare(T x, T y)
        {
            if (x.Equals(y)) return 0;
            return rdm.Next(3) - 1;
        }
    }

    enum Card3DGameMode
    {
        One,
        Four
    }

    /// <summary>
    /// 翻牌游戏
    /// </summary>
    class Card3DGame
    {
        #region 游戏属性

        private const double width = 7;  //卡牌宽度
        private const double height = 10; //卡牌高度
        private const double offset = 2;    //卡牌间隔
        private const int diaphaneity = 200; //画刷透明度

        private int jokerCount = 1; //鬼牌数量
        private int turnCount = 5; //每轮翻开卡牌数
        private int phase = 0; //当前阶段
        private int totalPhase = 0; //总阶段数，与基本画刷数量相等

        private List<Brush> basicBrushs = new List<Brush>(); //基本画刷列表
        private List<Brush> frontBrushs = new List<Brush>(); //游戏中的基本画刷列表
        private List<Card3DModel> cardList = new List<Card3DModel>(); //卡牌列表
        private List<Card3DModel> tmpCardList = new List<Card3DModel>(); //临时卡牌列表
        private Card3DModel cardModel = new Card3DModel(new Point3D(0, 0, 0), width, height); //样板卡牌
 
        private DispatcherTimer timer = new DispatcherTimer(); //倒记时器
        private Label lbTxt = new Label(); //游戏提示 1
        private Label lbImg = new Label(); //游戏提示 2
       
        private Stopwatch stopWatch = new Stopwatch(); //记时器
        private double searchTime = 0; //总查找时间

        #endregion

        #region 外部接口

        /// <summary>
        /// 游戏视图
        /// </summary>
        private Grid gameGrid = new Grid();
        /// <summary>
        /// 获取游戏视图
        /// </summary>
        public Grid GameGrid
        {
            get { return gameGrid; }
        }

        /// <summary>
        /// 记忆时间
        /// </summary>
        private int rememberTime = 20;
        /// <summary>
        /// 获取或设置记忆时间
        /// </summary>
        public int RememberTime
        {
            get { return rememberTime; }
            set { rememberTime = value; }
        }

        /// <summary>
        /// 背景画刷
        /// </summary>
        private Brush backBrush = new SolidColorBrush(Colors.Black);
        /// <summary>
        /// 获取或设置背景画刷
        /// </summary>
        public Brush BackBrush
        {
            get { return backBrush; }
            set { backBrush = value; }
        }

        /// <summary>
        /// 鬼牌画刷
        /// </summary>
        private Brush jokerBrush = new SolidColorBrush(Colors.Black);
        /// <summary>
        /// 获取或设置特殊鬼牌画刷
        /// </summary>
        public Brush JokerBrush
        {
            get { return jokerBrush; }
            set { jokerBrush = value; }
        }

        /// <summary>
        /// 构造器
        /// </summary>
        public Card3DGame()
        {
            InitMaterialBrush(); //初始化材质画刷
            InitView(); //初始化控件
            InitTimer(); //初始化时钟控件
        }

        /// <summary>
        /// 初始化游戏
        /// </summary>
        public void NewGame()
        {
            timer.Stop();

            lbTxt.Content = null;
            lbImg.Content = null;

            cardModel.FrontBrush = null;
            cardModel.BackBrush = null;

            phase = 0; //初始为一阶段
            searchTime = 0; //统计时间清 0 
            tmpCardList.Clear(); //清空临时列表

            InitCard3DModel();
            InitBrushs();
        }

        /// <summary>
        /// 开始游戏
        /// </summary>
        public void StartGame()
        {
            RememberPhase();
        }

        /// <summary>
        /// 切换模式
        /// </summary>
        public void ChangeMode(Card3DGameMode mode)
        {
            if (mode == Card3DGameMode.One)
            {
                jokerCount = 1;
                turnCount = 5;
            }
            else
            {
                jokerCount = 4;
                turnCount = 4;
            }
        }

        #endregion

        #region 初始化函数

        //初始化所有画刷 
        private void InitMaterialBrush()
        {
            basicBrushs.Add(new SolidColorBrush(Color.FromArgb((byte)diaphaneity, 255, 0, 0))); //红色
            basicBrushs.Add(new SolidColorBrush(Color.FromArgb((byte)diaphaneity, 0, 255, 0))); //绿色
            basicBrushs.Add(new SolidColorBrush(Color.FromArgb((byte)diaphaneity, 0, 0, 255))); //蓝色
            totalPhase = basicBrushs.Count;
        }
        //初始化 Grid
        private void InitView()
        {
            gameGrid.RowDefinitions.Add(new RowDefinition());
            gameGrid.RowDefinitions.Add(new RowDefinition());
            gameGrid.RowDefinitions[0].Height = new GridLength(10, GridUnitType.Star);
            gameGrid.RowDefinitions[1].Height = new GridLength(2, GridUnitType.Star);

            gameGrid.ColumnDefinitions.Add(new ColumnDefinition());
            gameGrid.ColumnDefinitions.Add(new ColumnDefinition());
            gameGrid.ColumnDefinitions[0].Width = new GridLength(10, GridUnitType.Star);
            gameGrid.ColumnDefinitions[1].Width = new GridLength(2, GridUnitType.Star);

            gameGrid.Children.Add(lbTxt);
            lbTxt.SetValue(Grid.RowProperty, 1);
            lbTxt.FontSize = 30;
            lbTxt.HorizontalContentAlignment = HorizontalAlignment.Right;
            lbTxt.VerticalContentAlignment = VerticalAlignment.Center;

            gameGrid.Children.Add(lbImg);
            lbImg.SetValue(Grid.RowProperty, 1);
            lbImg.SetValue(Grid.ColumnProperty, 1);
            lbImg.FontSize = 30;
            lbImg.HorizontalContentAlignment = HorizontalAlignment.Center;
            lbImg.VerticalContentAlignment = VerticalAlignment.Center;

            cardModel.Create3DCard();
            cardModel.AllowMouse = false;
            cardModel.TurnCardCompleted += AfterModelCardTurn;
            gameGrid.Children.Add(cardModel);
            cardModel.SetValue(Grid.RowProperty, 1);
            cardModel.SetValue(Grid.ColumnProperty, 1);
        }
        //初始化时钟控件
        private void InitTimer()
        {
            timer.Tick += TimeTickEvent;
            timer.Interval = TimeSpan.FromSeconds(1);
        }
        //初始化模型
        private void InitCard3DModel()
        {
            foreach (Card3DModel card in cardList)
            {
                gameGrid.Children.Remove(card);
            }
            cardList.Clear();
            for (int i = -2; i < 2; i++)
            {
                for (int j = -2; j < 2; j++)
                {
                    Point3D point = new Point3D((offset + width) * j + (width / 2), (offset + height) * i + (height / 2), 0);
                    Card3DModel card = new Card3DModel(point, width, height, height * 10);
                    card.Create3DCard();
                    card.FrontBrush = null;
                    card.BackBrush = backBrush;
                    card.AllowMouse = false;
                    card.TurnCardCompleted += TurnOverCompleted;
                    //加入列表
                    cardList.Add(card);
                    gameGrid.Children.Add(card);
                    card.SetValue(Grid.RowProperty, 0);
                    card.SetValue(Grid.ColumnSpanProperty, 2);
                }
            }
        }
        //初始化画刷
        private void InitBrushs()
        {
            //把要用到的画刷根据要用到的个数加入总画刷列表
            frontBrushs.Clear();
            for (int i = 0; i < jokerCount; i++)
            {
                frontBrushs.Add(jokerBrush);
            }
            for (int i = 0; i < basicBrushs.Count; i++)
            {
                for (int j = 0; j < turnCount; j++)
                {
                    frontBrushs.Add(basicBrushs[i]);
                }
            }
        }
        //画刷乱序
        private void ShuffleCardBrush()
        {
            frontBrushs.Sort(new RandomComparer<Brush>());
            for (int i = 0; i < frontBrushs.Count; i++)
            {
                cardList[i].FrontBrush = frontBrushs[i];
            }
        }
        //乱序要查找的画刷
        private void ShuffleSearchBrush()
        {
            basicBrushs.Sort(new RandomComparer<Brush>());
        }

        #endregion

        #region 控制函数

        //进入记忆阶段
        private void RememberPhase()
        {
            ShuffleSearchBrush(); //乱序查找画刷
            ShuffleCardBrush(); //乱序画刷
            TurnCards(cardList, true, false); //打开所有卡牌
            lbTxt.Content = "请在" + rememberTime + "秒内记忆卡牌位置";
            lbImg.Content = rememberTime.ToString();
            timer.Tag = rememberTime;
            timer.Start();
        }
        //进入翻牌阶段
        private void SearchPhase()
        {
            TurnCards(cardList, false, true); //盖上所有卡牌
            //设置样板正反面
            if (cardModel.Status)
            {
                cardModel.FrontBrush = basicBrushs[phase];
                cardModel.BackBrush = basicBrushs[phase + 1];
            }
            else
            {
                cardModel.FrontBrush = basicBrushs[phase + 1];
                cardModel.BackBrush = basicBrushs[phase];
            }
            lbTxt.Content = " 请找出以下卡牌：";
            lbImg.Content = null;
            stopWatch.Reset(); //停止之前任何几时
            stopWatch.Start(); //开始记时
        }
        //普通错误处理
        private void ErrorPhase()
        {
            TurnCards(tmpCardList, false, true); //盖上已翻出的同一种牌
            tmpCardList.Clear();
        }
        //翻到特殊卡牌
        private void JokerPhase()
        {
            TurnCards(cardList, false, true); //盖上全部牌
            tmpCardList.Clear(); //清空临时列表
            ShuffleSearchBrush(); //刷新样板画刷次序
            phase = 0; //重头开始
            //设置样板的另一面
            if (cardModel.Status)
            {
                cardModel.BackBrush = basicBrushs[phase];
            }
            else
            {
                cardModel.FrontBrush = basicBrushs[phase];
            }
            cardModel.TurnCardOver();
        }
        //进入下一阶段
        private void NextPhase()
        {
            tmpCardList.Clear(); //清空临时列表
            ++phase; //翻下一种牌
            cardModel.TurnCardOver();
        }
        //游戏结束处理
        private void GameOver()
        {
            cardModel.FrontBrush = null;
            cardModel.BackBrush = null;
            foreach (Card3DModel card in cardList)
            {
                card.AllowMouse = false;
            }
            stopWatch.Stop();
            searchTime = stopWatch.ElapsedMilliseconds / 1000.0;
            lbTxt.Content = "游戏结束，共使用：" + searchTime + " 秒";
        }
        //翻转指定的卡牌，true　表示翻开， false 表示覆盖
        private void TurnCards(List<Card3DModel> cards, bool status, bool allowMouse)
        {
            foreach (Card3DModel card in cards)
            {
                card.AllowMouse = allowMouse; //是否可以点击
                if (card.Status == !status) //找出需要操作的牌
                {
                    card.IsCompleted = false;
                    card.TurnCardOver();
                }
            }
        }
        //翻转后判定
        private void TurnOverCompleted(object sender, EventArgs e)
        {
            Card3DModel card = (Card3DModel)sender;
            card.AllowMouse = false; //翻开的牌暂时不能重点
            if (card.FrontBrush == jokerBrush) //翻到特殊牌
            {
                JokerPhase(); //盖上所有牌
            }
            else if (card.FrontBrush == basicBrushs[phase]) //翻到正确的牌
            {
                tmpCardList.Add(card);
                if (tmpCardList.Count == turnCount && phase < totalPhase - 1) //如果翻满且未是最后一种牌
                {
                    NextPhase(); //翻下一种牌
                }
                else if (tmpCardList.Count == turnCount && phase == totalPhase - 1) //如果翻满且是最后一种牌
                {
                    GameOver(); //游戏结束
                }
            }
            else //否则
            {
                tmpCardList.Add(card);
                ErrorPhase(); //盖上当前种类的牌
            }
        }
        //样板卡牌翻转后
        private void AfterModelCardTurn(object sender, EventArgs e)
        {
            if (phase < totalPhase - 1)
            {
                if (cardModel.Status)
                {
                    cardModel.BackBrush = basicBrushs[phase + 1];
                }
                else
                {
                    cardModel.FrontBrush = basicBrushs[phase + 1];
                }
            }
        }
        //时钟控件触发事件
        private void TimeTickEvent(object sender, EventArgs e)
        {
            int count = (int)timer.Tag;
            if (count <= 0)
            {
                timer.Stop(); //计时结束
                SearchPhase(); //时间到达后触发事件
            }
            else
            {
                timer.Tag = --count; //倒计时
                lbImg.Content = count.ToString();
            }
        }

        #endregion
    }
}